import socket
from header import *
from rdt_function import *
from multiprocessing import Process,Queue


serverAddress = '127.0.0.1'
deport = 9999
bufferSize = 1024
target = (serverAddress, deport)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(target)
split = "|:|"
pk_to_send = ""
serverWinsize = 50

receive_win_size_in_lget = 50
m_in_lget = 0
currentAck_in_lget = 0
currentSend_in_lget = 0
current_cache_in_lget = []
buffer_in_lget = ''
totalAck = 0
q = Queue()
pack_cache = []
serverport = 9000

def lget_re(sock,f,):
    global receive_win_size_in_lget
    global m_in_lget
    global currentAck_in_lget_s
    global currentSend_in_lget
    global current_cache_in_lget
    global buffer_in_lget
    global totalAck
    global q

    while 1:
        print("ggggggggggggggggggggggggggg")
        data,addr = sock.recvfrom(1024)
        pk = Packet()
        pk.decode(data)
        receive_win_size_in_lget = pk.receiveWindowSize

        if pk.seqNo != 0:
            q.put(pk.seqNo)
        else:
            currentAck_in_lget_s = pk.ackNo
            print("total ack "+str(totalAck))
            print("curr_ack"+str(currentAck_in_lget_s))
            for p in current_cache_in_lget:
                if p.ackNo == currentAck_in_lget_s:
                    current_cache_in_lget.remove(p)
        if currentAck_in_lget_s == totalAck:
            m_in_lget = 1
        else:
            m_in_lget = 0
        if currentAck_in_lget_s == totalAck:
            break

def lget(port, address, f, filesize):
    sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    sock.bind(('127.0.0.1',port))
    global receive_win_size_in_lget
    global m_in_lget
    global currentAck_in_lget_s
    global currentSend_in_lget
    global current_cache_in_lget
    global buffer_in_lget
    global totalAck
    global q

    thread1 = threading.Thread(target=lget_re, args=(sock,f,))#recv
    thread1.start()

    mode = filesize%200

    add = 0
    if mode != 0:
        add = 1
    totalAck = int(filesize/200) + add

    while 1:

        if receive_win_size_in_lget > 0:

            if not q.empty():
                currentAck_in_lget_s = q.get()
                for p in current_cache_in_lget:
                    if p.ackNo == currentAck:
                        buffer = p.data
                pk.make({'seqNo': 0, 'ackNo': currentAck_in_lget_s, 'receiveWindowSize': 50, 'ACK': 0, 'SYN': 0, 'FIN': m_in_lget, 'data': buffer})
                sock.sendto(pk.bitStream, address)
            else:
                if currentSend_in_lget != totalAck + 1:
                    buffer_in_lget = f.read(200)
                    pk = Packet()
                    print("send"+str(currentSend_in_lget+1))
                    currentSend_in_lget = currentSend_in_lget + 1
                    if currentSend_in_lget == totalAck:
                        m_in_lget = 1
                    pk.make({'seqNo': 0, 'ackNo': currentSend_in_lget, 'receiveWindowSize': receive_win_size_in_lget, 'ACK': 0, 'SYN': 0, 'FIN': m_in_lget, 'data': buffer_in_lget})
                    current_cache_in_lget.append(pk)
                    print("total "+str(totalAck))
                    print("cerrent_send "+str(currentSend_in_lget))
                    time.sleep(0.03)
                    sock.sendto(pk.bitStream, address)
                else:
                    print("in close")
                    f.close()
                    break


def send_ack(address, f):
    global currentAck_in_lget
    global tag
    global tag_finish
    global pack_cache
    while 1:
        tag = False
        tag_finish = False
        print("2222222222222222222222")
        #pk.make({'seqNo': 0, 'ackNo': 0, 'receiveWindowSize': 50-len(pack_cache), 'ACK': 0, 'SYN': 0, 'FIN': 0,'data':''.encode('utf-8')})
        print(pack_cache)
        for p in pack_cache:
            print("111111111111111111111")
            print("curr "+str(currentAck_in_lget))
            print("p.ack "+str(p.ackNo))
            if p.ackNo == currentAck_in_lget+1:
                tag = True
                pk = p
                f.write(pk.data)
                fin = pk.FIN
                if fin == 1:
                    tag_finish = True
                pk_back = Packet()
                currentWinSize = 50-len(pack_cache)
                pk_back.make({'seqNo': 0, 'ackNo': pk.ackNo, 'receiveWindowSize': currentWinSize, 'ACK': 0, 'SYN': 0, 'FIN': 0})
                sock.sendto(pk_back.bitStream, address)
                currentAck_in_lget = p.ackNo
                pack_cache.remove(p)
                break
            else:
                pass

        if tag == False&len(pack_cache) != 0:
            pk_back = Packet()
            currentWinSize = 50-len(pack_cache)
            pk_back.make({'seqNo': currentAck_in_lget, 'ackNo': 0, 'receiveWindowSize': currentWinSize, 'ACK': 0, 'SYN': 0, 'FIN': 0})
            sock.sendto(pk_back.bitStream, address)

        if tag_finish:
            break

def lsend(serverport, address, f, filesize):
    global pack_cache

    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.bind(('127.0.0.1',serverport))
    thread_sendAck = threading.Thread(target=send_ack, args=(address,f,))
    thread_sendAck.start()
    global currentAck
    while 1:
        #print("in lget")
        if len(pack_cache) < 50:
            #print("lget"+str(pack_cache))
            data,addr = sock.recvfrom(1024)
            print(data)
            pk = Packet()
            pk.decode(data)
            print("receive packet "+str(pk.ackNo))
            pk.decode(data)

            pack_cache.append(pk)
            #print(pack_cache)
            print("ok.Fin"+str(pk.FIN))
            if pk.FIN == 1:
                break


while 1:
    currentAck = 0
    data = 0
    address = 0
    data, address = sock.recvfrom(1024)
    print(data)
    pk = Packet()
    pk.decode(data)
    ackNo = pk.ackNo
    pk_ack = Packet()
    print(ackNo)
    pk_ack.make({'seqNo': 0, 'ackNo': ackNo, 'receiveWindowSize': 50, 'ACK': 0, 'SYN':0, 'FIN': 0,'data':str(serverport).encode('utf-8')})

    sock.sendto(pk_ack.bitStream, address)
    # send add
    target = (address, deport)
    rdt_send_for_server(address, pk_ack.bitStream, sock, pk.ackNo)
    #sock.sendto(pk_ack.bitStream,address)

    method_and_filename = pk.data.decode('utf-8')
    method_and_filename = method_and_filename.split(split)
    method = method_and_filename[0]
    filename = method_and_filename[1]
    clientport = int(method_and_filename[2])
    print(method)
    print(filename)

    if method == 'lsend':
        try:
            f = open("server/"+filename, 'wb')
            filesize = os.path.getsize("server/"+filename)
        except:
            print("open file error")

        thread_lsend = threading.Thread(target=lsend, args=(serverport, (address[0], clientport), f, filesize))#send
        serverport = serverport + 1
        thread_lsend.start()
        thread_lsend.join()

    elif method == 'lget':
        print("into lget")
        try:
            f = open("server/"+filename, 'rb')
            filesize = os.path.getsize("server/"+filename)
        except:
            print("open file error")

        print(filesize)

        thread_lget = threading.Thread(target=lget, args=(serverport, (address[0], clientport), f, filesize))#send
        serverport = serverport + 1
        thread_lget.start()
        thread_lget.join()

    else:
        pass
